using System;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using Unity.Collections.LowLevel.Unsafe;


namespace AnimCollections {
    /// <summary>
    /// 
    /// </summary>
    [DebuggerTypeProxy(typeof(NativeSimpleArrayDebugView<>))]
    public unsafe struct NativeSimpleArray<T> : IDisposable
        where T : unmanaged {
        internal void* m_Buffer;
        internal int m_Length;

        public int Length {
            [MethodImpl(MethodImplOptions.AggressiveInlining)]
            get => m_Length;
        }
        public T* Ptr {
            [MethodImpl(MethodImplOptions.AggressiveInlining)]
            get => (T*)m_Buffer;
        }

        /// 不了解就别用
        public void UnsafeSetBufferPtr(ulong addr) {
            m_Buffer = (void*)addr;
        }

        public bool IsCreated {
            [MethodImpl(MethodImplOptions.AggressiveInlining)]
            get => m_Buffer != null;
        }

        public void Dispose() {
            m_Buffer = null;
        }

        public T this[int index] {
            [MethodImpl(MethodImplOptions.AggressiveInlining)]
            get {
                CheckIndex(index);
                return UnsafeUtility.ReadArrayElement<T>(m_Buffer, index);
            }
            [MethodImpl(MethodImplOptions.AggressiveInlining)]
            set {
                CheckIndex(index);
                UnsafeUtility.WriteArrayElement<T>(m_Buffer, index, value);
            }
        }

        public ref T GetRefAt(int index) {
            CheckIndex(index);
            return ref UnsafeUtility.ArrayElementAsRef<T>(m_Buffer, index);
        }

        public T* GetPtrAt(int index) {
            CheckIndex(index);
            return (T*)((IntPtr)m_Buffer + (index * sizeof(T)));
        }

        public void* GetUnsafePtr() {
            return m_Buffer;
        }

        public void CopyFrom(T[] src) {
            GCHandle gCHandle = GCHandle.Alloc(src, GCHandleType.Pinned);
            IntPtr intPtr = gCHandle.AddrOfPinnedObject();
            UnsafeUtility.MemCpy(m_Buffer, (void*)intPtr, src.Length * sizeof(T));
        }

        [Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS")]
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private void CheckIndex(int index) {
            if (index >= m_Length || index < 0)
                throw new IndexOutOfRangeException();
        }
    }

    internal class NativeSimpleArrayDebugView<T> where T : unmanaged {
        private NativeSimpleArray<T> m_Array;

        public NativeSimpleArrayDebugView(NativeSimpleArray<T> array) {
            m_Array = array;
        }

        public unsafe T[] Items {
            get {
                if (!m_Array.IsCreated) {
                    return null;
                }

                int length = m_Array.m_Length;
                T[] array = new T[length];
                GCHandle gCHandle = GCHandle.Alloc(array, GCHandleType.Pinned);
                IntPtr intPtr = gCHandle.AddrOfPinnedObject();
                UnsafeUtility.MemCpy((void*)intPtr, m_Array.m_Buffer, length * UnsafeUtility.SizeOf<T>());
                gCHandle.Free();
                return array;
            }
        }
    }
}
